<template>
	<view class="uni-calendar" v-if="show">
		<view class="uni-calendar__mask" @click="maskClick" v-if="!insert"></view>
		<view class="uni-calendar__content" :class="{
			'uni-calendar__content--insert': insert
		}">
			<view class="uni-calendar__header">
				<view class="uni-calendar__header-btn" @click="prevMonth">
					<text class="uni-calendar__header-btn-text">‹</text>
				</view>
				<view class="uni-calendar__header-text">
					{{ currentYear }}年{{ currentMonth }}月
				</view>
				<view class="uni-calendar__header-btn" @click="nextMonth">
					<text class="uni-calendar__header-btn-text">›</text>
				</view>
			</view>
			<view class="uni-calendar__weeks">
				<view class="uni-calendar__weeks-item" v-for="week in weeks" :key="week">
					{{ week }}
				</view>
			</view>
			<view class="uni-calendar__dates">
				<view class="uni-calendar__dates-item" 
					v-for="(date, index) in dates" 
					:key="index"
					:class="{
						'uni-calendar__dates-item--disabled': date.disabled,
						'uni-calendar__dates-item--selected': date.selected,
						'uni-calendar__dates-item--today': date.isToday,
						'uni-calendar__dates-item--other-month': date.otherMonth
					}"
					@click="selectDate(date)">
					{{ date.day }}
				</view>
			</view>
			<view class="uni-calendar__footer" v-if="!insert">
				<view class="uni-calendar__footer-btn" @click="cancel">
					取消
				</view>
				<view class="uni-calendar__footer-btn uni-calendar__footer-btn--confirm" @click="confirm">
					确定
				</view>
			</view>
		</view>
	</view>
</template>

<script>
/**
 * uni-calendar 日历
 * @description 日历组件可以查看日期，选择任意范围内的日期，打点操作。常用场景如：酒店日期预订、火车机票选择购买日期、上下班打卡等
 */
export default {
	name: 'uni-calendar',
	props: {
		// 日期
		date: {
			type: [String, Object],
			default: ''
		},
		// 是否插入模式
		insert: {
			type: Boolean,
			default: false
		},
		// 开始时间
		startDate: {
			type: String,
			default: ''
		},
		// 结束时间
		endDate: {
			type: String,
			default: ''
		},
		// 范围选择
		range: {
			type: Boolean,
			default: false
		}
	},
	data() {
		return {
			show: false,
			currentYear: 0,
			currentMonth: 0,
			dates: [],
			weeks: ['日', '一', '二', '三', '四', '五', '六'],
			selectedDate: null,
			selectedRange: []
		};
	},
	mounted() {
		this.init();
	},
	methods: {
		// 初始化
		init() {
			const now = new Date();
			this.currentYear = now.getFullYear();
			this.currentMonth = now.getMonth() + 1;
			this.generateDates();
		},
		// 生成日期数据
		generateDates() {
			const year = this.currentYear;
			const month = this.currentMonth;
			const firstDay = new Date(year, month - 1, 1);
			const lastDay = new Date(year, month, 0);
			const firstDayWeek = firstDay.getDay();
			const daysInMonth = lastDay.getDate();
			
			const dates = [];
			const today = new Date();
			const todayStr = this.formatDate(today);
			
			// 上个月的日期
			const prevMonth = month === 1 ? 12 : month - 1;
			const prevYear = month === 1 ? year - 1 : year;
			const prevMonthDays = new Date(prevYear, prevMonth, 0).getDate();
			
			for (let i = firstDayWeek - 1; i >= 0; i--) {
				const day = prevMonthDays - i;
				dates.push({
					day,
					date: new Date(prevYear, prevMonth - 1, day),
					otherMonth: true,
					disabled: false,
					selected: false,
					isToday: false
				});
			}
			
			// 当前月的日期
			for (let i = 1; i <= daysInMonth; i++) {
				const date = new Date(year, month - 1, i);
				const dateStr = this.formatDate(date);
				dates.push({
					day: i,
					date,
					otherMonth: false,
					disabled: this.isDisabled(dateStr),
					selected: false,
					isToday: dateStr === todayStr
				});
			}
			
			// 下个月的日期
			const nextMonth = month === 12 ? 1 : month + 1;
			const nextYear = month === 12 ? year + 1 : year;
			const remainingDays = 42 - dates.length;
			
			for (let i = 1; i <= remainingDays; i++) {
				dates.push({
					day: i,
					date: new Date(nextYear, nextMonth - 1, i),
					otherMonth: true,
					disabled: false,
					selected: false,
					isToday: false
				});
			}
			
			this.dates = dates;
		},
		// 格式化日期
		formatDate(date) {
			const year = date.getFullYear();
			const month = String(date.getMonth() + 1).padStart(2, '0');
			const day = String(date.getDate()).padStart(2, '0');
			return `${year}-${month}-${day}`;
		},
		// 判断是否禁用
		isDisabled(dateStr) {
			if (this.startDate && dateStr < this.startDate) return true;
			if (this.endDate && dateStr > this.endDate) return true;
			return false;
		},
		// 上一月
		prevMonth() {
			if (this.currentMonth === 1) {
				this.currentYear--;
				this.currentMonth = 12;
			} else {
				this.currentMonth--;
			}
			this.generateDates();
		},
		// 下一月
		nextMonth() {
			if (this.currentMonth === 12) {
				this.currentYear++;
				this.currentMonth = 1;
			} else {
				this.currentMonth++;
			}
			this.generateDates();
		},
		// 选择日期
		selectDate(date) {
			if (date.disabled || date.otherMonth) return;
			
			if (this.range) {
				// 范围选择逻辑
				if (this.selectedRange.length === 0) {
					this.selectedRange.push(date.date);
				} else if (this.selectedRange.length === 1) {
					this.selectedRange.push(date.date);
					this.selectedRange.sort((a, b) => a - b);
				} else {
					this.selectedRange = [date.date];
				}
			} else {
				// 单选逻辑
				this.selectedDate = date.date;
				this.dates.forEach(d => d.selected = false);
				date.selected = true;
			}
		},
		// 打开日历
		open() {
			this.show = true;
		},
		// 关闭日历
		close() {
			this.show = false;
		},
		// 遮罩点击
		maskClick() {
			this.close();
			this.$emit('cancel');
		},
		// 取消
		cancel() {
			this.close();
			this.$emit('cancel');
		},
		// 确认
		confirm() {
			let result;
			if (this.range) {
				result = {
					range: this.selectedRange.map(date => this.formatDate(date))
				};
			} else {
				result = {
					fulldate: this.selectedDate ? this.formatDate(this.selectedDate) : ''
				};
			}
			this.close();
			this.$emit('confirm', result);
		}
	}
};
</script>

<style scoped lang="scss">
.uni-calendar {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 999;
	display: flex;
	align-items: center;
	justify-content: center;
	
	&__mask {
		position: absolute;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		background-color: rgba(0, 0, 0, 0.4);
	}
	
	&__content {
		background-color: #fff;
		border-radius: 12rpx;
		margin: 40rpx;
		max-width: 600rpx;
		width: 100%;
		position: relative;
		z-index: 1;
		
		&--insert {
			margin: 0;
			border-radius: 0;
			max-width: none;
		}
	}
	
	&__header {
		display: flex;
		align-items: center;
		justify-content: space-between;
		padding: 30rpx;
		border-bottom: 1px solid #ebeef5;
		
		&-btn {
			width: 60rpx;
			height: 60rpx;
			display: flex;
			align-items: center;
			justify-content: center;
			border-radius: 50%;
			background-color: #f5f7fa;
			
			&-text {
				font-size: 32rpx;
				color: #606266;
			}
		}
		
		&-text {
			font-size: 32rpx;
			font-weight: bold;
			color: #303133;
		}
	}
	
	&__weeks {
		display: flex;
		padding: 20rpx 0;
		border-bottom: 1px solid #ebeef5;
		
		&-item {
			flex: 1;
			text-align: center;
			font-size: 28rpx;
			color: #909399;
			height: 60rpx;
			line-height: 60rpx;
		}
	}
	
	&__dates {
		display: flex;
		flex-wrap: wrap;
		padding: 20rpx 0;
		
		&-item {
			width: 14.28%;
			height: 80rpx;
			display: flex;
			align-items: center;
			justify-content: center;
			font-size: 28rpx;
			color: #303133;
			position: relative;
			
			&--disabled {
				color: #c0c4cc;
				cursor: not-allowed;
			}
			
			&--selected {
				background-color: #409eff;
				color: #fff;
				border-radius: 50%;
			}
			
			&--today {
				color: #409eff;
				font-weight: bold;
			}
			
			&--other-month {
				color: #c0c4cc;
			}
		}
	}
	
	&__footer {
		display: flex;
		justify-content: flex-end;
		padding: 30rpx;
		border-top: 1px solid #ebeef5;
		
		&-btn {
			padding: 16rpx 32rpx;
			margin-left: 20rpx;
			border-radius: 8rpx;
			font-size: 28rpx;
			color: #606266;
			background-color: #f5f7fa;
			
			&--confirm {
				background-color: #409eff;
				color: #fff;
			}
		}
	}
}
</style>